#include "datacenter.h"

// 初始化实例
model::DataCenter* model::DataCenter::instance = nullptr;

model::DataCenter::DataCenter():netClient(this) {
    // 这⼏个 哈希表 提前把对象 new 好
    recentMessages = new QHash<QString, QList<Message>>();
    memberList = new QHash<QString, QList<UserInfo>>();
    unreadMessageCount = new QHash<QString, int>();
    loadDataFile();
}

model::DataCenter::~DataCenter()
{
    delete myself;
    delete friendList;
    delete chatSessionList;
    delete memberList;
    delete recentMessages;
    delete searchMessageResult;
    delete unreadMessageCount;
    delete searchUserResult;
}

void model::DataCenter::initDataFile()
{
    // 拼装⼀个⽂件⽬录. 使⽤ appData 作为⽬录
    QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/ChatClient.json";

    // 打开⽂件
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        qCritical() << TAG << "Cannot open file:" << file.errorString() <<
            filePath;
        return;
    }

    // 写⼊初始内容
    QString data = "{\n\n}";
    file.write(data.toUtf8());
    file.close();
}

void model::DataCenter::saveDataFile()
{
    // 拼装⼀个⽂件⽬录. 使⽤ appData 作为⽬录
    QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) +"/ChatClient.json";
    // 打开⽂件
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        qCritical() << TAG << "Cannot open file:" << file.errorString() <<
            filePath;
        return;
    }
    // 写⼊ loginSessionId
    QJsonObject jsonObj;
    jsonObj["loginSessionId"] = loginSessionId;
    // 写⼊未读消息次数
    QJsonObject jsonUnread;
    for (auto it = unreadMessageCount->begin(); it != unreadMessageCount->end(); ++it) {
        jsonUnread[it.key()] = it.value();
    }
    jsonObj["unread"] = jsonUnread;
    // 写⼊⽂件
    QJsonDocument jsonDoc(jsonObj);

    QString s = jsonDoc.toJson();
    // LOG() << "saveData: s=" << s;
    file.write(s.toUtf8());
    // 关闭⽂件. QFile 能在析构的时候⾃动关闭
    file.close();
}

void model::DataCenter::loadDataFile()
{
    // 拼装⼀个⽂件⽬录. 使⽤ appData 作为⽬录
    QString basePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
    QString filePath = basePath + "/ChatClient.json";
    // 如果⽬录不存在, 就先创建⽬录
    QDir dir;
    if (!dir.exists(basePath)) {
        dir.mkpath(basePath);
    }
    // 如果⽂件不存在, 就先创建⽂件
    QFileInfo fileInfo(filePath);
    if (!fileInfo.exists()) {
        initDataFile();
    }
    // 读⽅式打开⽂件.
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qCritical() << TAG << "Cannot open file:" << file.errorString() <<
            filePath;
        return;
    }
    // 读取⽂件内容, 解析为 JSON
    QJsonDocument jsonDoc = QJsonDocument::fromJson(file.readAll());
    if (jsonDoc.isNull()) {
        qCritical() << TAG << "Invalid JSON format";
        return;
    }
    // 获取到 JSON 中的属性
    QJsonObject jsonObj = jsonDoc.object();
    loginSessionId = jsonObj["loginSessionId"].toString();
    this->unreadMessageCount->clear();

    QJsonObject unread = jsonObj["unread"].toObject();
    for (auto it = unread.constBegin(); it != unread.constEnd(); ++it) {
        // qDebug() << "key:" << it.key() << " value:" << it.value().toInt();
        (*this->unreadMessageCount)[it.key()] = it.value().toInt();
    }
    // 检查读到的内容是否正确
    if (loginSessionId == "") {
        qCritical() << TAG << "读取到的 sessionId 为空!";
        return;
    }
}

const QString &model::DataCenter::getLoginSessionId()
{
    return loginSessionId;
}

model::UserInfo *model::DataCenter::getMyselfInfo()
{
    return myself;
}

void model::DataCenter::setMySelfInfo(std::shared_ptr<lx::GetUserInfoRsp> resp)
{
    if(myself == nullptr){
        myself = new UserInfo();
    }

    const lx::UserInfo& userInfo = resp->userInfo();
    myself->load(userInfo);
}

QList<model::UserInfo> *model::DataCenter::getFriendList()
{
    return friendList;
}

void model::DataCenter::getFriendListAsync()
{
    netClient.getFriendList(loginSessionId);
}

void model::DataCenter::setFriendList(std::shared_ptr<lx::GetFriendListRsp> resp)
{
    if(!friendList){
        friendList = new QList<UserInfo>();
    }

    friendList->clear();

    auto& FriendLsitPB = resp->friendList();
    for(auto& u : FriendLsitPB){
        UserInfo userInfo;
        userInfo.load(u);

        friendList->push_back(userInfo);
    }

}

QList<model::ChatSessionInfo> *model::DataCenter::getSessionList()
{
    return chatSessionList;
}

void model::DataCenter::getSessionListAsync()
{
    netClient.getSessionList(loginSessionId);
}

void model::DataCenter::setSessionList(std::shared_ptr<lx::GetChatSessionListRsp> resp)
{
    if(chatSessionList == nullptr){
        chatSessionList = new QList<ChatSessionInfo>();
    }
    chatSessionList->clear();

    const auto& sessionList = resp->chatSessionInfoList();

    for(const auto& s : sessionList){
        ChatSessionInfo chatSessionInfo;
        chatSessionInfo.load(s);
        chatSessionList->push_back(chatSessionInfo);
    }
}

void model::DataCenter::getApplyListAsync()
{
    netClient.getApplyList(loginSessionId);
}

void model::DataCenter::setApplyList(std::shared_ptr<lx::GetPendingFriendEventListRsp> resp)
{
    if(applyList == nullptr){
        applyList = new QList<UserInfo>();
    }
    applyList->clear();

    const auto& applyListPB = resp->event();

    for(const auto& a : applyListPB){
        UserInfo userInfo;
        userInfo.load(a.sender());

        applyList->push_back(userInfo);
    }
}

void model::DataCenter::getRencentMessagesAsync(const QString &chatSessionId, bool isUpdateUI)
{
    netClient.getRecentMessages(loginSessionId, chatSessionId, isUpdateUI);
}

void model::DataCenter::setRecentMessages(const QString &chatSessionId, std::shared_ptr<lx::GetRecentMsgRsp> resp)
{
    QList<model::Message>& messages = (*recentMessages)[chatSessionId];
    messages.clear();

    auto& messagesPB = resp->msgList();
    for(const auto& m : messagesPB){
        model::Message message;
        message.load(m);

        messages.push_back(message);
    }


}

model::ChatSessionInfo* model::DataCenter::getChatSessionInfo(const QString &chatSessioId)
{
    if(chatSessionList == nullptr){
        return nullptr;
    }

    for( auto& c : *chatSessionList){
        if(chatSessioId == c.chatSessionId){
            return &c;
        }
    }
    return nullptr;
}

void model::DataCenter::setCurrentChatSessionId(const QString &chatSessionId)
{
    currentChatSessionId = chatSessionId;
}

const QString &model::DataCenter::getCurrentChatSessionId()
{
    return currentChatSessionId;
}

void model::DataCenter::topChatSessionInfo(ChatSessionInfo chatSessionInfo)
{
    if(chatSessionList == nullptr){
        return;
    }

    auto it = chatSessionList->begin();
    for(;it != chatSessionList->end(); ++it){
        if(it->chatSessionId == chatSessionInfo.chatSessionId){
            break;
        }
    }

    if(it == chatSessionList->end()){
        return;
    }

    //拷贝一份该元素
    ChatSessionInfo copy = chatSessionInfo;
    //删除该元素
    chatSessionList->erase(it);
    //头插
    chatSessionList->push_front(copy);
}

void model::DataCenter::sendTextMessageAsync(const QString &chatSessionId, const QString& content)
{
    netClient.sendMessage(loginSessionId, chatSessionId, MessageType::TEXT_TYPE, content.toUtf8(),"");
}

const model::ChatSessionInfo *model::DataCenter::getChatSessionInfoByUserId(const QString &userId)
{
    if(chatSessionList == nullptr){
        return nullptr;
    }

    for(auto& c : *chatSessionList){
        if(c.userId == userId){
            return &c;
        }
    }

    return nullptr;
}

void model::DataCenter::addMessage(const model::Message& message){
    auto& messageList = (*recentMessages)[message.chatSessionId];
    messageList.push_back(message);
}

QList<model::Message> *model::DataCenter::getRecentMessages(const QString& chatSessionId)
{
    if(!recentMessages->contains(chatSessionId)){
        return nullptr;
    }

    return &(*recentMessages)[chatSessionId];
}

QList<model::UserInfo> *model::DataCenter::getApplyList()
{
    return applyList;
}

void model::DataCenter::getMyselfInfoAsync()
{
    netClient.getMyselfInfo(loginSessionId);
}

model::DataCenter *model::DataCenter::getInstance()
{
    if(instance == nullptr){
        instance = new DataCenter();
    }

    return instance;
}

//添加未读消息数
void model::DataCenter::addUnread(const QString& chatSessionId){
    ++(*unreadMessageCount)[chatSessionId];
    // 保存到⽂件中
    saveDataFile();
}

//清空未读消息数
void model::DataCenter::clearUnread(const QString& chatSessionId){
    (*unreadMessageCount)[chatSessionId] = 0;
    // 保存到⽂件中
    saveDataFile();
}

//获取到未读消息数
int model::DataCenter::getUnread(const QString &chatSessionId)
{
    return (*unreadMessageCount)[chatSessionId];
}

void model::DataCenter::receiveMessage(const QString &chatSessionId)
{
    //如果消息是来⾃于当前被选中会话, 那么直接把消息展⽰到消息展⽰区
    if(chatSessionId == currentChatSessionId){
        //获取最后一条消息
        const model::Message message  = (*recentMessages)[chatSessionId].back();

        //通过信号告知界⾯要添加⼀个新消息
        emit this->receiveMessageDone(message);
    }
    else{
        addUnread(chatSessionId);
    }

    //再发个信号, 更新会话列表中的显⽰的 lastMessage
    emit this->updateLastMessage(chatSessionId);
}

void model::DataCenter::changeNickNameAsync(const QString &name)
{
    netClient.changeNickName(loginSessionId, name);
}

void model::DataCenter::setName(const QString &name)
{
    myself->nickname = name;
}

void model::DataCenter::changeDescriptionAsync(const QString &description)
{
    netClient.changeDescription(loginSessionId, description);
}

void model::DataCenter::setDescription(const QString &description)
{
    myself->description = description;
}

void model::DataCenter::getVerifyCodeAsync(const QString &phone)
{
    netClient.getVerifyCode(phone);
}


void model::DataCenter::setPhone(const QString &phone)
{
    myself->phone = phone;
}

void model::DataCenter::setVerifyCodeId(const QString &verifyCodeId)
{
    this->currentVerifyCodeId = verifyCodeId;
}

const QString &model::DataCenter::getVerifyCodeId()
{
    return currentVerifyCodeId;
}

void model::DataCenter::changePhoneAsync(const QString &phone, const QString &verifyCodeId, const QString &verifyCode)
{
    netClient.changePhone(loginSessionId, phone, verifyCodeId, verifyCode);
}

void model::DataCenter::changeAvatarAsync(const QByteArray &avatar)
{
    netClient.changeAvatar(loginSessionId, avatar);
}

void model::DataCenter::setAvatar(const QByteArray &avatar)
{
    myself->avatar = makeIcon(avatar);
}

model::UserInfo *model::DataCenter::getFriendById(const QString &userId)
{
    if (friendList == nullptr) {
        return nullptr;
    }
    for (auto& f : *friendList) {
        if (f.userId == userId) {
            return &f;
        }
    }
    return nullptr;
}

void model::DataCenter::deleteFriendAsync(const QString &userId)
{
    netClient.deleteFriend(loginSessionId, userId);
}

void model::DataCenter::removeFriend(const QString &userId)
{
    friendList->removeIf([=](const UserInfo& userInfo) {
        return userInfo.userId == userId;
    });

    chatSessionList->removeIf([=](const ChatSessionInfo& chatSessionInfo) {
        if (chatSessionInfo.userId == "") {
            // 群聊会话不受影响.
            return false;
        }
        if (chatSessionInfo.userId != userId) {
            return false;
        }
        if (chatSessionInfo.chatSessionId == this->currentChatSessionId) {
            // 如果当前要删除的会话就是正在选中的会话, 则清空当前会话内容
            emit this->clearCurrentSession();
        }
        return true;
    });
}

void model::DataCenter::addFriendApplyAsync(const QString &userId)
{
    netClient.addFriendApply(loginSessionId, userId);
}

void model::DataCenter::acceptFriendApplyAsync(const QString &userId)
{
    netClient.acceptFriendApply(loginSessionId, userId);
}

model::UserInfo model::DataCenter::removeFromApplyList(const QString &userId)
{
    if(applyList == nullptr){
        return model::UserInfo();
    }

    for(int i = 0; i < applyList->size(); ++i){
        if(applyList->at(i).userId == userId){
            model::UserInfo userInfo = applyList->at(i);
            applyList->removeAt(i);
            return userInfo;
        }
    }
    return model::UserInfo();
}

void model::DataCenter::rejectFriendApplyAsync(const QString &userId)
{
    netClient.rejectFriendApply(loginSessionId, userId);
}

model::UserInfo* model::DataCenter::getUserInfoByuserId(const QString &userId)
{
    if(friendList == nullptr){
        return nullptr;
    }

    for(auto& u : *friendList){
        if(u.userId == userId){
            return &u;
        }
    }

    return nullptr;
}

void model::DataCenter::createChatSessionAsync(const QList<QString> &userIdList)
{
    netClient.createChatSession(loginSessionId, userIdList);
}

void model::DataCenter::getMemberListAsync(const QString &chatSessionId)
{
    netClient.getMemberList(loginSessionId, chatSessionId);
}

void model::DataCenter::setMemberList(const QString &chatSessionId, std::shared_ptr<lx::GetChatSessionMemberRsp> resp)
{
    // 先清空原有数据
    QList<UserInfo>& curMemberList = (*memberList)[chatSessionId];
    curMemberList.clear();
    // 添加元素到成员列表中
    for (auto& m : resp->memberInfoList()) {
        UserInfo userInfo;
        userInfo.load(m);
        curMemberList.push_back(userInfo);
    }
}

QList<model::UserInfo> *model::DataCenter::getMemberList(const QString &chatSessionId)
{
    if(memberList == nullptr){
        return nullptr;
    }

    if (!this->memberList->contains(chatSessionId)) {
        return nullptr;
    }
    return &(*this->memberList)[chatSessionId];
}

void model::DataCenter::searchUserAsync(const QString &searchKey)
{
    netClient.searchUser(loginSessionId, searchKey);
}

void model::DataCenter::setSearchUserResult(std::shared_ptr<lx::FriendSearchRsp> resp)
{
    // 1. 创建出实例
    if (searchUserResult == nullptr) {
        searchUserResult = new QList<UserInfo>();
    }
    // 2. 清空之前的内容
    searchUserResult->clear();
    // 3. 添加当前响应的结果
    for (const auto& u : resp->userInfo()) {
        UserInfo userInfo;
        userInfo.load(u);
        searchUserResult->push_back(userInfo);
    }
}

void model::DataCenter::searchMessageAsync(const QString &searchKey)
{
    netClient.searchMessage(loginSessionId, currentChatSessionId, searchKey);
}

void model::DataCenter::setSearchMessageResult(const QList<lx::MessageInfo> &msgList)
{
    // 1. 创建出实例
    if (searchMessageResult == nullptr) {
        searchMessageResult = new QList<Message>();
    }
    // 2. 清空之前的结果
    searchMessageResult->clear();

    // 3. 添加当前数据到结果中
    for (const auto& m : msgList) {
        Message message;
        message.load(m);
        searchMessageResult->push_back(message);
    }
}

QList<model::Message> *model::DataCenter::getSearchMessageResult()
{
    return searchMessageResult;
}

void model::DataCenter::searchMessageByTimeAsync(const QDateTime begTime, const QDateTime endTime)
{
    netClient.searchMessageByTime(loginSessionId, currentChatSessionId, begTime, endTime);
}

void model::DataCenter::userLoginAsync(const QString &username, const QString &password)
{
    netClient.userLogin(username, password);
}

void model::DataCenter::setLoginSessionId(const QString &loginSessionId)
{
    this->loginSessionId = loginSessionId;
    saveDataFile();
}

void model::DataCenter::userRegisterAsync(const QString &username, const QString &password)
{
    netClient.userRegister(username, password);
}

void model::DataCenter::phoneLoginAsync(const QString &phone, const QString &phoneVerifyCode)
{
    netClient.phoneLogin(phone, phoneVerifyCode);
}

void model::DataCenter::phoneRegisterAsync(const QString &phone, const QString &phoneVerifyCode)
{
    netClient.phoneRegister(phone, phoneVerifyCode);
}


QList<model::UserInfo> *model::DataCenter::getSearchUserResult()
{
    return searchUserResult;
}

